﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Linq;
using NHibernate.Criterion;
using System.Linq.Expressions;
using System.Reflection;
using System.Linq.Dynamic;
using Entidades;
using Common;
using Persistence;

namespace Persistencia.Repositorios
{
    public class PagoRepositorio
    {
        private readonly ISession _session;

        #region Constructors

        /// <summary>
        /// Constructor por defecto
        /// </summary>
        public PagoRepositorio()
        {
            try
            {
                _session = NHibernateSessionHelper.GetSession();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Devuelve el Pago de un Proveedor, asociado a un Guion, y una Fecha de grabacion
        /// </summary>
        /// <returns></returns>
        public Pago ObtenerPago(int idProveedor, int idRolProveedor, int idGuion, int idEstado)
        {
            var pago = default(Pago);
            try
            {
                using (var transaction = _session.BeginTransaction())
                {
                    pago = _session.Query<Pago>().FirstOrDefault
                        (
                            x => x.Guion.Id == idGuion &&
                            x.Proveedor.Id == idProveedor &&
                            x.ProveedorRol.Id == idRolProveedor &&
                            x.Estado.Id == idEstado
                            //(x.Fecha.Year == fecha.Year && x.Fecha.Month == fecha.Month && x.Fecha.Day == fecha.Day)
                        );
                }
            }
            catch (Exception)
            {
                throw;
            }
            return pago;
        }

        /// <summary>
        /// Devuelve los Pagos correspondientes a una lista de Guiones, según un Estado de Pago y un Tipo de Usuario (opcional)
        /// </summary>
        /// <param name="idsGuiones"></param>
        /// <param name="idEstadoPago"></param>
        /// <param name="idTipoUsuario"></param>
        /// <param name="idCategoriaUsuario"></param>
        /// <returns></returns>
        public IList<Pago> ObtenerPagos(int[] idsGuiones, int idEstadoPago, int? idTipoUsuario = null, int? idCategoriaUsuario = null)
        {
            var pagos = new List<Pago>();
            try
            {
                using (var transaction = _session.BeginTransaction())
                {
                    var query = _session.Query<Pago>()
                        .Where
                        (
                            x => idsGuiones.Contains(x.Guion.Id) &&
                            x.Guion.Estado.Id == WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id &&
                            x.Estado.Id == idEstadoPago
                        );

                    if ( idTipoUsuario.HasValue )
                        query = query.Where(x => x.Proveedor.Tipo.Id == idTipoUsuario);

                    if ( idCategoriaUsuario.HasValue )
                        query = query.Where(x => x.Proveedor.Categoria.Id == idCategoriaUsuario);

                    pagos = query.OrderBy(x => x.Guion.Proyecto.Id).ToList();
                }
            }
            catch (Exception)
            {
                throw;
            }
            return pagos;
        }

        /// <summary>
        /// Devuelve los Pagos correspondientes a una lista de Pagos
        /// [Opcional] Rol de Proveedor
        /// [Opcional] Categoría de Proveedor
        /// [Opcional] Tipo de Proveedor ignorado
        /// [Opcional] Categoría de Proveedor ignorada
        /// </summary>
        /// <param name="idsPagos"></param>
        /// <param name="idEstadoPago"></param>
        /// <param name="idRolProveedor"></param>
        /// <param name="idCategoriaProveedor"></param>
        /// <param name="idRolProveedorIgnorado"></param>
        /// <param name="idCategoriaProveedorIgnorada"></param>
        /// <returns></returns>
        public IList<Pago> ObtenerPagosSegunListaDePagos(int[] idsPagos, int idEstadoPago, int? idRolProveedor = null, int? idCategoriaProveedor = null, int? idRolProveedorIgnorado = null, int? idCategoriaProveedorIgnorada = null)
        {
            var pagos = new List<Pago>();
            try
            {
                using (var transaction = _session.BeginTransaction())
                {
                    var query = _session.Query<Pago>()
                        .Where
                        (
                            x => idsPagos.Contains(x.Id) &&
                            x.Guion.Estado.Id == WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id &&
                            x.Estado.Id == idEstadoPago
                        );

                    if ( idRolProveedor.HasValue )
                        query = query.Where(x => x.ProveedorRol.Id == idRolProveedor);

                    if ( idRolProveedorIgnorado.HasValue )
                        query = query.Where(x => x.ProveedorRol.Id != idRolProveedorIgnorado);

                    if ( idCategoriaProveedor.HasValue )
                        query = query.Where(x => x.Proveedor.Categoria.Id == idCategoriaProveedor);

                    if ( idCategoriaProveedorIgnorada.HasValue )
                        query = query.Where(x => x.Proveedor.Categoria.Id != idCategoriaProveedorIgnorada);

                    pagos = query.OrderBy(x => x.Guion.Proyecto.Id).ToList();
                }
            }
            catch (Exception)
            {
                throw;
            }
            return pagos;
        }

        /// <summary>
        /// Guarda un Pago
        /// </summary>
        /// <param name="guion"></param>
        /// <returns></returns>
        public bool GuardarPago(Pago pago)
        {
            var resultado = false;
            try
            {
                using (ITransaction transaction = _session.BeginTransaction())
                {
                    _session.SaveOrUpdate(pago);
                    _session.Flush();
                    transaction.Commit();
                    resultado = true;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return resultado;    
        }

        #endregion
    }
}
